<template>
    <div class="content" ref="content" id="content">
        <!-- <Loading v-if="!loadingPercentage.completed" size="220" color="#03b2c9" :text="loadingPercentage.percentage"
            dot-count="6" /> -->
        <img src="/loading/home.png" v-if="!loadingPercentage.completed" class="gjp" alt="">
        <div ref="container" class="three-container"
            :style="{ width: `calc(100vw - ${containerOffsetLeft})`, height: `calc(100vh - ${containerOffsetTop})` }">
        </div>
        <BottomContent v-if="loadingPercentage.completed" :itemList="[]">
            <template #default>
                <div class="button-list" v-if="isHideSheBei">
                    <div class="button" @click="showModuleQiang(true)">
                        <img src="@/assets/three/button-background.svg" alt="">
                        <div class="label">
                            关闭设备
                        </div>
                    </div>
                </div>
                <div class="button-list" v-if="!isHideSheBei">
                    <div class="button" @click="showModuleQiang(false)">
                        <img src="@/assets/three/button-background.svg" alt="">
                        <div class="label">
                            显示设备
                        </div>
                    </div>
                </div>
                <div class="button-list" v-if="isHideGuanDao">
                    <div class="button" @click="hideGuanDao(true)">
                        <img src="@/assets/three/button-background.svg" alt="">
                        <div class="label">
                            关闭管网
                        </div>
                    </div>
                </div>
                <div class="button-list" v-if="!isHideGuanDao">
                    <div class="button" @click="showGuanDaoMoudle">
                        <img src="@/assets/three/button-background.svg" alt="">
                        <div class="label">
                            显示管网
                        </div>
                    </div>
                </div>
            </template>
        </BottomContent>
    </div>
</template>

<script setup async>
import { ref, onMounted, onBeforeUnmount, defineEmits, defineProps, } from 'vue'
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass'
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader'
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass'
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
import { CSS2DRenderer, CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer"

import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js'
import { TilesRenderer } from '3d-tiles-renderer'
import { gsap } from 'gsap'
import Loading from '@/components/Loading'
import { useFullscreen } from '@vueuse/core'
import 'animate.css/animate.min.css';
import { Group, Tween, Easing } from '@tweenjs/tween.js'
import textBackground from '@/assets/three/text-bac.png';
import lineBackground from '@/assets/three/icon-sjx.svg';
import autofit from "autofit.js";

const props = defineProps({
    outlinePass: {
        type: Boolean,
        default: true
    }
})
const emit = defineEmits(['loadingFinish']);
// DOM 引用
const container = ref(null)
const containerOffsetLeft = ref('200px');
const containerOffsetTop = ref('85');

const content = ref(null)
const { toggle } = useFullscreen(content)

// 1. 创建独立的tween组
const tweenGroup = new Group()

const loadingPercentage = ref({
    percentage: '',
    completed: false
})

// Three.js 核心对象
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(65, 1, 0.1, 70000)
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

let renderer = null;
let controls = null;
let composer = null;
let css2Renderer = null;
const gltfGroup = new THREE.Group()
const css2dRendererGroup = new THREE.Group()
const boundingPlanesGroup = new THREE.Group()
const topGroup = new THREE.Group()
let outlinePass, tilesRendererModules = [];
let modulItem = null, guandaoModule = null;
let isHideSheBei = ref(false);
let isHideGuanDao = ref(false);
// 资源管理
const resources = {
    textures: [],
    models: [],
    geometries: [],
    materials: [],
    eventListeners: [],
    animations: []
}

defineExpose([
    scene,
    camera,
    renderer,
])
// 模型配置
const gltfArray = [
    // { url: '/scyy/tuoshuichejian.glb', labelText: '脱水车间', isBbox: false },
    // { url: '/scyy/jixioufang.glb', labelText: '机修房', isBbox: false },
    // { url: '/scyy/pinghengchi.glb', labelText: '平衡池', isBbox: false },
    // { url: '/scyy/nonsuochi.glb', labelText: '浓缩池', isBbox: false },
    // { url: '/scyy/chendianchi.glb', labelText: '沉淀池', isBbox: false },
    // { url: '/scyy/jiayaojian.glb', labelText: '加药间', isBbox: false },
    // { url: '/scyy/painichi.glb', labelText: '排泥池', isBbox: false },
    // { url: '/scyy/shitan.glb', labelText: '食堂', isBbox: false },
    // { url: '/scyy/v-lvchi.glb', labelText: 'V型滤池', isBbox: false },
    // { url: '/scyy/qingshuichi.glb', labelText: '清水池', isBbox: false },
    // { url: '/scyy/guandao.glb', labelText: '', isBbox: false },
    // { url: '/scyy/gzgli.glb', labelText: '', isBbox: false },
    { url: '/modules/home.glb', labelText: '', isBbox: false },
]

let selectedForOutline = {
    'jiayaojian': [],
    'chendianchi': [],
    'tuoshuijifang': [],
    'shitang': [],
    'qingshuichi': [],
    'Vxinshuiche': [],
    'nonsuochi': [],
    'painichi': [],
};
const titlesPaths = [
    // '/scyy/changdi/tileset.json',
]

// 加载管理器
const loadingManager = new THREE.LoadingManager(
    () => {
        loadingPercentage.value.completed = true;
        emit('loadingFinish', scene);
        // const router = new Tween(camera.position,
        //     tweenGroup // 关键：传入组实例
        // ).to({ x: 0, y: 140, z: 110 }, 2000)
        //     .easing(Easing.Quartic.Out)
        //     .onUpdate((obj) => {
        //         camera.updateProjectionMatrix()
        //         controls?.update()
        //     })
        //     .start().onComplete(() => {
        //         // 设置模型的中心
        //         // 设置模型的中心
        //         tweenGroup.remove(router);
        //         // emit('loadingFinish', scene);
        //         // controls.minDistance = 50;  // 最小缩放距离（默认0）
        //         controls.maxPolarAngle = Math.PI * 0.35; // 最大俯角（避免完全倒置）
        //     })
    },
    (url, loaded, total) => {
        loadingPercentage.value.percentage = `加载中..${((loaded / total) * 100).toFixed(2)}%`
    }
)


// 初始化场景
const initScene = async () => {

    // 初始化渲染器
    renderer = new THREE.WebGLRenderer({
        antialias: true,
        logarithmicDepthBuffer: true
    })
    renderer.outputEncoding = THREE.sRGBEncoding; // 色彩空间
    renderer.toneMapping = THREE.ACESFilmicToneMapping; // 色调映射
    renderer.logarithmicDepthBuffer = true;
    renderer.toneMappingExposure = 1.2; // 曝光度（间接影响环境亮度） 白天
    updateRendererSize()
    container.value.appendChild(renderer.domElement)

    camera.position.set(-6, 60, 70)
    camera.updateProjectionMatrix()

    // 初始化控制器
    controls = new OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true
    controls.minDistance = 20;  // 最小缩放距离（默认0）
    controls.maxDistance = 160; // 最大缩放距离（默认Infinity）
    controls.target.set(-6, 0, 16)
    controls.maxPolarAngle = Math.PI * 0.35; // 最大俯角（避免完全倒置）

    // 设置场景背景
    scene.background = new THREE.Color('#02004d')

    // 初始化后期处理和标签渲染器
    initPostProcessing()
    createCSS2DRenderer()

    // 加载模型和环境
    gltfArray.forEach((item) => {
        loadModel(item)
    })

    loadEnvironment()

    scene.add(gltfGroup)
    scene.add(css2dRendererGroup)
    scene.add(boundingPlanesGroup)
}


// 创建标签
const createLabel = (text) => {
    const label = document.createElement("div")
    label.style.cursor = 'pointer';
    label.style.pointerEvents = 'auto';
    label.innerHTML = `
        <div class='animate__animated animate__bounceIn' style="display: flex;align-items: center;flex-direction: column;justify-content: center;">
            <div style="width:130px;height: 55px;position: relative;">
                <img src="${textBackground}" style="width:130px;height: 55px;" />
                <div class="label-text" style="position:absolute;top:12px;left:0;right:0;margin: 0 auto;text-align: center;color:#fff;font-size:18px;">${text}</div>    
            </div>
            <img src="${lineBackground}" style="width: 34px;height: 44px;margin-top: -10px;" />    
        </div>
    `
    return label
}
// 创建CSS2D渲染器
const createCSS2DRenderer = () => {
    css2Renderer = new CSS2DRenderer()
    updateCSS2DRendererSize()
    css2Renderer.domElement.style.position = 'absolute'
    css2Renderer.domElement.style.top = '0'
    css2Renderer.domElement.style.pointerEvents = 'none'
    container.value.appendChild(css2Renderer.domElement)
}

// 初始化后期处理
const initPostProcessing = () => {
    composer = new EffectComposer(renderer)

    // 添加RenderPass（带色调映射）
    const renderPass = new RenderPass(scene, camera);
    renderPass.toneMapping = renderer.toneMapping;
    renderPass.toneMappingExposure = renderer.toneMappingExposure;
    composer.addPass(renderPass);

    const fxaaPass = new ShaderPass(FXAAShader)
    const pixelRatio = renderer.getPixelRatio()
    fxaaPass.material.uniforms['resolution'].value.x = 1 / (container.value.clientWidth * pixelRatio)
    fxaaPass.material.uniforms['resolution'].value.y = 1 / (container.value.clientHeight * pixelRatio)
    composer.addPass(fxaaPass)

    const outputPass = new OutputPass();
    outputPass.toneMapping = THREE.NoToneMapping; // 避免二次处理
    outputPass.outputColorSpace = THREE.sRGBColorSpace; // r152+
    composer.addPass(outputPass);

    if (props.outlinePass) {
        // 4. 创建描边效果
        outlinePass = new OutlinePass(
            new THREE.Vector2(container.value.clientWidth, container.value.clientHeight),
            scene,
            camera
        );
        outlinePass.edgeStrength = 3.0; // 描边强度
        outlinePass.edgeGlow = 0.5;     // 边缘发光
        outlinePass.edgeThickness = 1.0; // 边缘厚度
        outlinePass.pulsePeriod = 2;    // 脉冲周期
        outlinePass.visibleEdgeColor.set('#ff0000'); // 可见边颜色
        outlinePass.hiddenEdgeColor.set('#ff0000');  // 隐藏边颜色
        composer.addPass(outlinePass);
        window.addEventListener('mousemove', onMouseMove);
    }
}


let idNames = {
    'tuoshuijifang': '脱水机房',
    'nonsuochi': '浓缩池',
    'qingshuichi': '清水池',
    'gongzuojian': '工作间',
    'painichi': '排泥池',
    'shitang': '食堂',
    'painiche': '排泥池',
    'jixiufang': '机修房',
    'jiayaojian': '加药间',
    'chendianchi': '沉淀池',
    'Vxinshuiche': 'V型滤池',
    'pinghengche': '平衡池',
    'A': '工作间',
}
// 安全获取 Object3D（容错：数组 / {object:...} / 直接就是 Object3D）
function asObject3D(entry) {
    if (!entry) return null;
    if (entry.isObject3D) return entry;
    if (Array.isArray(entry)) return entry[0] && entry[0].isObject3D ? entry[0] : null;
    if (entry.object && entry.object.isObject3D) return entry.object;
    return null;
}

// 计算 group(或任意 Object3D) 的世界包围盒（会自动更新矩阵并补 computeBoundingBox）
function getWorldBox(obj3d) {
    // 先确保 worldMatrix 是最新的
    obj3d.updateMatrixWorld(true);

    // 遍历所有子 Mesh，补几何体的 boundingBox
    obj3d.traverse((child) => {
        if (child.isMesh && child.geometry && !child.geometry.boundingBox) {
            try { child.geometry.computeBoundingBox(); } catch { }
        }
    });

    const box = new THREE.Box3();
    box.setFromObject(obj3d);
    return box;
}
function onMouseMove(event) {
    // 获取容器相对于视口的坐标位置
    const rect = container.value.getBoundingClientRect();

    // 计算容器内的相对鼠标坐标 (考虑滚动偏移)
    const mouseX = event.clientX - rect.left;
    const mouseY = event.clientY - rect.top;

    // 转换为标准化设备坐标 (NDC: -1到1)
    mouse.x = (mouseX / rect.width) * 2 - 1;
    mouse.y = -(mouseY / rect.height) * 2 + 1;

    // 更新射线检测
    raycaster.setFromCamera(mouse, camera);

    const intersects = raycaster.intersectObjects(topGroup.children);

    if (intersects.length > 0) {
        const modul = intersects[0]?.object.parent;
        const [name] = modul.name.split("_");
        outlinePass.selectedObjects = selectedForOutline[name] || [];

        let css2dModule = css2dRendererGroup.children.find(item=>item.resetName===idNames[name]);
        if(css2dModule){
            css2dModule.visible = true;
            return;
        }
        // === 你原来的逻辑，改成用上面的工具函数 ===
        const obj3d = asObject3D(selectedForOutline[name]);
        if (!obj3d) {
            console.warn('selectedForOutline[name] 不是有效的 Object3D：', selectedForOutline[name]);
        } else {
            const box = getWorldBox(obj3d);
            if (box.isEmpty()) {
                console.warn('该组没有有效几何体，包围盒为空：', obj3d);
            } else {
                const center = new THREE.Vector3();
                box.getCenter(center);
                
                const div = createLabel(idNames[name]);
                const labelObject = new CSS2DObject(div);

                // 世界坐标：中心点的正上方
                labelObject.position.set(center.x, box.max.y, center.z);
                labelObject.center.set(0.5, 1);
                labelObject.resetName = idNames[name];
                // 如果 css2dRendererGroup 是放在 scene 根下，以上世界坐标可直接加进去：
                css2dRendererGroup.add(labelObject);
            }
        }
    } else {
        outlinePass.selectedObjects = [];
        css2dRendererGroup.children.forEach(item => {
            item.visible = false;
        })
    }
}

const showModuleQiang = (value = false) => {
    gltfGroup.children.forEach(module => {
        module.traverse((item) => {
            if (['shang', 'qian', 'zuo', 'you', 'hou', 'YOU'].includes(item.name.split('_')[1]?.replace(/\d/g, ''))) {
                item.children.forEach(child => {
                    child.visible = value;
                });
            }
        })
    })
    isHideSheBei.value = !value;
}
const showProcess = (value = false) => {

}
const showGuanDaoMoudle = () => {
    isHideGuanDao.value = true;
    guandaoModule.children.forEach(child => {
        if (child.isMesh) {
            child.material.depthWrite = true;
            child.material.depthTest = false;
            child.material.transparent = true;
        }
    });

}
const hideGuanDao = () => {
    isHideGuanDao.value = false;
    guandaoModule.children.forEach(child => {
        if (child.isMesh) {
            child.material.depthWrite = true;
            child.material.depthTest = true;
            child.material.transparent = true;
        }
    });
}
// 加载环境贴图
const loadEnvironment = () => {
    const loader = new THREE.TextureLoader();
    const tex = loader.load('/hdre_426_meadow_hill_hdri.jpg', () => {
        tex.mapping = THREE.EquirectangularReflectionMapping;  // 或者直接用球面贴图
        tex.colorSpace = THREE.SRGBColorSpace;
        scene.background = tex;        // 只当背景
        tex.anisotropy = renderer.capabilities.getMaxAnisotropy();
        // 可选：也用作环境（让建筑有“天空反射”）
    });
    // 设置天空盒子
    const textureCubeLoader = new THREE.CubeTextureLoader();
    const textureCube = textureCubeLoader.load([
        '/textureCube/posx.jpg',
        '/textureCube/negx.jpg',
        '/textureCube/posy.jpg',
        '/textureCube/negy.jpg',
        '/textureCube/posz.jpg',
        '/textureCube/negz.jpg',
    ]);
    scene.environment = textureCube;
    const ambient = new THREE.AmbientLight(0xf5f5f5, 2);
    scene.add(ambient);
}


// 加载模型
const loadModel = ({ url, labelText, isBbox, sg }) => {
    const loader = new GLTFLoader(loadingManager)
    const dracoLoader = new DRACOLoader()
    dracoLoader.setDecoderPath("/draco/gltf/")
    dracoLoader.setDecoderConfig({ type: "js" })
    loader.setDRACOLoader(dracoLoader)
    loader.load(url, (gltf) => {
        const model = gltf.scene
        model.traverse((item) => {
            if (item.isMesh) {
                if (item.name == 'EXPORT_GOOGLE_SAT_WM') {
                    const texture = item.material.map;
                    item.material = new THREE.MeshBasicMaterial({ map: texture });
                }
            }
            const [name, id] = item.name.split('_');
            if (['shang', 'qian', 'zuo', 'you', 'hou', 'YOU'].includes(id?.replace(/\d/g, ''))) {
                topGroup.add(item.clone())
                if (!selectedForOutline[name]) selectedForOutline[name] = [];
                selectedForOutline[name].push(...item.children);
            }
            if (item.name == 'guandao001') {
                guandaoModule = item;
            }
        })
        resources.models.push(model)

        model.resetName = labelText
        gltfGroup.add(model)
    }, (error) => {

    })
}

// 更新渲染器尺寸
const updateRendererSize = () => {
    if (!container.value) return

    const width = container.value.clientWidth
    const height = container.value.clientHeight

    camera.aspect = width / height
    camera.updateProjectionMatrix()
    renderer?.setSize(width, height)

    // 更新后期处理器
    if (composer) {
        composer.setSize(width, height)
        const passes = composer.passes
        for (let i = 0; i < passes.length; i++) {
            if (passes[i] instanceof ShaderPass && passes[i].material.uniforms['resolution']) {
                const pixelRatio = renderer.getPixelRatio()
                passes[i].material.uniforms['resolution'].value.x = 1 / (width * pixelRatio)
                passes[i].material.uniforms['resolution'].value.y = 1 / (height * pixelRatio)
            }
        }
    }
}

// 更新CSS2D渲染器尺寸
const updateCSS2DRendererSize = () => {
    if (!container.value || !css2Renderer) return
    const width = container.value.clientWidth
    const height = container.value.clientHeight
    css2Renderer.setSize(width, height)
}

// 主动画循环
const animate = () => {
    try {
        if (!container.value) return
        const rect = container.value.getBoundingClientRect()
        if (rect) {
            containerOffsetLeft.value = rect.left + 'px';
            containerOffsetTop.value = rect.top + 'px';
            renderer?.setSize(rect.width, rect.height)
            camera.aspect = rect.width / rect.height
            camera.updateProjectionMatrix()
            css2Renderer?.setSize(rect.width, rect.height)
            css2Renderer?.render(scene, camera)
        }

        composer?.render()
        controls?.update();
        requestAnimationFrame(animate)

        tilesRendererModules.forEach(tiles => tiles.update());

        // 更新 Tween 动画
        tweenGroup.update();
    } catch (error) {

    }
}

// 窗口大小变化处理
const handleResize = () => {
    updateRendererSize()
    updateCSS2DRendererSize()
}
// 组件挂载
onMounted(() => {
    initScene()
    animate()
    window.addEventListener('resize', handleResize)
    document.onmousedown = () => {
        try {
            let moduls = outlinePass?.selectedObjects;
            moduls.forEach(item => {
                item.visible = false;
                isHideSheBei.value = true
            })
        } catch (error) {
            isHideSheBei.value = false
        }
    }
})

// 组件卸载前清理
onBeforeUnmount(() => {
    // 移除事件监听
    window.removeEventListener('resize', handleResize)
    window.removeEventListener('mousemove', onMouseMove);

    // 清理动画
    resources.animations.forEach(anim => anim.kill())

    // 清理事件监听器
    resources.eventListeners.forEach(({ element, handler }) => {
        element?.removeEventListener('click', handler)
    })

    // 清理场景
    scene.traverse(object => {
        if (!object.isMesh) return

        if (object.geometry) {
            object.geometry.dispose()
        }

        if (object.material) {
            if (Array.isArray(object.material)) {
                object.material.forEach(m => m.dispose())
            } else {
                object.material.dispose()
            }
        }
    })
    // 清理纹理
    resources.textures.forEach(texture => {
        texture.dispose()
        texture.image?.close?.()
    })

    // 清理渲染器
    if (renderer) {
        container.value?.removeChild(renderer.domElement)
        renderer.dispose()
    }

    // 清理CSS2D渲染器
    if (css2Renderer) {
        container.value?.removeChild(css2Renderer.domElement)
    }

    // 清理控制器
    controls?.dispose();

    // 清理GSAP
    gsap.globalTimeline.clear();

    tweenGroup.removeAll();

})
</script>

<style scoped lang="scss">
.three-container {
    width: 100vw;
    height: 100vh;
    position: relative;
    overflow: hidden;
}

.content {
    width: 100%;
    height: 100%;
    position: relative;
}

:deep(.center-bottom-content) {
    width: 30%;
}

.button-list {
    display: flex;
    justify-content: center;
    width: 100%;

    .button {
        position: relative;
        width: 132px;
        height: 60px;
        text-align: center;
        line-height: 50px;
        cursor: pointer;
        margin: 0 20px;

        >img {
            position: absolute;
            z-index: -1;
            left: 0;
            width: 132px;
            height: 60px;
        }

        .label {
            width: 132px;
            font-size: 16px;
            text-align: center;
            color: #66FFFF;
        }
    }
}
.gjp {
    position: absolute;
    height: 100%;
    width: 100%;
    z-index: 999;
}
</style>